import math

import torch
import torch.nn as nn
import torch.nn.functional as F


def conv1x1(in_planes, out_planes, stride=1):
    """
    1x1卷积层，用于调整通道数。

    参数:
        in_planes (int): 输入通道数。
        out_planes (int): 输出通道数。
        stride (int, 可选): 步幅，默认值为1。

    返回:
        nn.Conv2d: 1x1卷积层。
    """
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)


class qkv_transform(nn.Conv1d):
    """
    QKV转换层，继承自1D卷积层。
    """
    pass


class medt_net(nn.Module):
    """
    MedT网络模型，结合了全局和局部特征提取。

    参数:
        block (nn.Module): 基础块类型，用于构建网络层。
        block_2 (nn.Module): 第二种基础块类型，用于构建网络层。
        layers (list): 每个阶段的块数列表。
        num_classes (int, 可选): 分类类别数，默认值为2。
        zero_init_residual (bool, 可选): 是否对残差连接进行零初始化，默认值为True。
        groups (int, 可选): 分组数，默认值为8。
        width_per_group (int, 可选): 每组的宽度，默认值为64。
        replace_stride_with_dilation (list, 可选): 是否用膨胀卷积替代步幅，默认值为None。
        norm_layer (nn.Module, 可选): 归一化层，默认使用BatchNorm2d。
        s (float, 可选): 缩放因子，默认值为0.125。
        img_size (int, 可选): 输入图像大小，默认值为224。
        imgchan (int, 可选): 输入图像的通道数，默认值为3。
    """

    def __init__(self, block, block_2, layers, num_classes=1, zero_init_residual=True,
                 groups=8, width_per_group=64, replace_stride_with_dilation=None,
                 norm_layer=None, s=0.125, img_size=224, imgchan=3):
        super(medt_net, self).__init__()

        # 选择归一化层，默认为BatchNorm2d
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        self._norm_layer = norm_layer

        # 初始化输入通道数
        self.inplanes = int(64 * s)
        self.dilation = 1

        # 处理是否用膨胀卷积替代步幅
        if replace_stride_with_dilation is None:
            replace_stride_with_dilation = [False, False, False]
        if len(replace_stride_with_dilation) != 3:
            raise ValueError("replace_stride_with_dilation should be None "
                             "or a 3-element tuple, got {}".format(replace_stride_with_dilation))

        self.groups = groups
        self.base_width = width_per_group

        # 定义初始卷积层
        self.conv1 = nn.Conv2d(imgchan, self.inplanes, kernel_size=7, stride=2, padding=3,
                               bias=False)
        self.conv2 = nn.Conv2d(self.inplanes, 128, kernel_size=3, stride=1, padding=1, bias=False)
        self.conv3 = nn.Conv2d(128, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)

        # 定义批归一化层
        self.bn1 = norm_layer(self.inplanes)
        self.bn2 = norm_layer(128)
        self.bn3 = norm_layer(self.inplanes)

        # 激活函数
        self.relu = nn.ReLU(inplace=True)

        # 定义网络层
        self.layer1 = self._make_layer(block, int(128 * s), layers[0], kernel_size=(img_size // 2))
        self.layer2 = self._make_layer(block, int(256 * s), layers[1], stride=2, kernel_size=(img_size // 2),
                                       dilate=replace_stride_with_dilation[0])
        # 注释掉的层可以根据需要启用
        # self.layer3 = self._make_layer(block, int(512 * s), layers[2], stride=2, kernel_size=(img_size//4),
        #                                dilate=replace_stride_with_dilation[1])
        # self.layer4 = self._make_layer(block, int(1024 * s), layers[3], stride=2, kernel_size=(img_size//8),
        #                                dilate=replace_stride_with_dilation[2])

        # 定义解码器层
        # self.decoder1 = nn.Conv2d(int(1024 *2*s), int(1024*2*s), kernel_size=3, stride=2, padding=1)
        # self.decoder2 = nn.Conv2d(int(1024  *2*s), int(1024*s), kernel_size=3, stride=1, padding=1)
        # self.decoder3 = nn.Conv2d(int(1024*s),  int(512*s), kernel_size=3, stride=1, padding=1)
        self.decoder4 = nn.Conv2d(int(512 * s), int(256 * s), kernel_size=3, stride=1, padding=1)
        self.decoder5 = nn.Conv2d(int(256 * s), int(128 * s), kernel_size=3, stride=1, padding=1)
        self.adjust = nn.Conv2d(int(128 * s), num_classes, kernel_size=1, stride=1, padding=0)
        self.soft = nn.Softmax(dim=1)

        # 定义另一个分支的卷积层
        self.conv1_p = nn.Conv2d(imgchan, self.inplanes, kernel_size=7, stride=2, padding=3,
                                 bias=False)
        self.conv2_p = nn.Conv2d(self.inplanes, 128, kernel_size=3, stride=1, padding=1,
                                 bias=False)
        self.conv3_p = nn.Conv2d(128, self.inplanes, kernel_size=3, stride=1, padding=1,
                                 bias=False)
        self.bn1_p = norm_layer(self.inplanes)
        self.bn2_p = norm_layer(128)
        self.bn3_p = norm_layer(self.inplanes)

        self.relu_p = nn.ReLU(inplace=True)

        # 计算局部分支的图像大小
        img_size_p = img_size // 4

        # 定义局部分支的网络层
        self.layer1_p = self._make_layer(block_2, int(128 * s), layers[0], kernel_size=(img_size_p // 2))
        self.layer2_p = self._make_layer(block_2, int(256 * s), layers[1], stride=2, kernel_size=(img_size_p // 2),
                                         dilate=replace_stride_with_dilation[0])
        self.layer3_p = self._make_layer(block_2, int(512 * s), layers[2], stride=2, kernel_size=(img_size_p // 4),
                                         dilate=replace_stride_with_dilation[1])
        self.layer4_p = self._make_layer(block_2, int(1024 * s), layers[3], stride=2, kernel_size=(img_size_p // 8),
                                         dilate=replace_stride_with_dilation[2])

        # 定义局部分支的解码器层
        self.decoder1_p = nn.Conv2d(int(1024 * 2 * s), int(1024 * 2 * s), kernel_size=3, stride=2, padding=1)
        self.decoder2_p = nn.Conv2d(int(1024 * 2 * s), int(1024 * s), kernel_size=3, stride=1, padding=1)
        self.decoder3_p = nn.Conv2d(int(1024 * s), int(512 * s), kernel_size=3, stride=1, padding=1)
        self.decoder4_p = nn.Conv2d(int(512 * s), int(256 * s), kernel_size=3, stride=1, padding=1)
        self.decoder5_p = nn.Conv2d(int(256 * s), int(128 * s), kernel_size=3, stride=1, padding=1)

        self.decoderf = nn.Conv2d(int(128 * s), int(128 * s), kernel_size=3, stride=1, padding=1)
        self.adjust_p = nn.Conv2d(int(128 * s), num_classes, kernel_size=1, stride=1, padding=0)
        self.soft_p = nn.Softmax(dim=1)

    def _make_layer(self, block, planes, blocks, kernel_size=56, stride=1, dilate=False):
        """
        构建一个网络层，包括多个基本块。

        参数:
            block (nn.Module): 基础块类型。
            planes (int): 输出通道数。
            blocks (int): 块的数量。
            kernel_size (int, 可选): 卷积核大小，默认值为56。
            stride (int, 可选): 步幅，默认值为1。
            dilate (bool, 可选): 是否使用膨胀卷积，默认值为False。

        返回:
            nn.Sequential: 由多个块组成的序列模块。
        """
        norm_layer = self._norm_layer
        downsample = None
        previous_dilation = self.dilation
        if dilate:
            self.dilation *= stride
            stride = 1
        # 判断是否需要下采样
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                conv1x1(self.inplanes, planes * block.expansion, stride),
                norm_layer(planes * block.expansion),
            )

        layers = []
        # 添加第一个块，可能包含下采样
        layers.append(block(self.inplanes, planes, stride, downsample, groups=self.groups,
                            base_width=self.base_width, dilation=previous_dilation,
                            norm_layer=norm_layer, kernel_size=kernel_size))
        self.inplanes = planes * block.expansion
        if stride != 1:
            kernel_size = kernel_size // 2

        # 添加后续的块
        for _ in range(1, blocks):
            layers.append(block(self.inplanes, planes, groups=self.groups,
                                base_width=self.base_width, dilation=self.dilation,
                                norm_layer=norm_layer, kernel_size=kernel_size))

        return nn.Sequential(*layers)

    def _forward_impl(self, x):
        """
        前向传播实现。

        参数:
            x (torch.Tensor): 输入张量。

        返回:
            torch.Tensor: 输出张量。
        """
        # 保存原始输入
        xin = x.clone()

        # 全局分支的前向传播[图中的紫色块]
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x)
        x = self.relu(x)
        x = self.conv3(x)
        x = self.bn3(x)
        x = self.relu(x)

        # 通过网络层
        x1 = self.layer1(x)  # [全局分支的红色块1]
        x2 = self.layer2(x1)  # [全局分支的红色块2]
        # 注释掉的层可以根据需要启用
        # x3 = self.layer3(x2)
        # x4 = self.layer4(x3)

        # 全局分支的解码过程
        # x = F.relu(F.interpolate(self.decoder1(x4), scale_factor=(2,2), mode='bilinear'))
        # x = torch.add(x, x4)
        # x = F.relu(F.interpolate(self.decoder2(x4) , scale_factor=(2,2), mode='bilinear'))
        # x = torch.add(x, x3)
        # x = F.relu(F.interpolate(self.decoder3(x3) , scale_factor=(2,2), mode='bilinear'))
        # x = torch.add(x, x2)
        x = F.relu(F.interpolate(self.decoder4(x2), scale_factor=(2, 2), mode='bilinear'))  # 上采样x2
        x = torch.add(x, x1)  # 拼接入块与出块（残差连接）
        x = F.relu(F.interpolate(self.decoder5(x), scale_factor=(2, 2), mode='bilinear'))  # 恢复原尺寸

        # 保存全局分支的特征图
        x_loc = x.clone()

        # 局部分支的前向传播（分块处理）
        # TODO 是不是因为修改了图像尺寸导致了有部分图像没有切割到，这里的range改错(0,7)试试？
        for i in range(0, 7):
            for j in range(0, 7):
                # 切分输入图像为32x32的块
                x_p = xin[:, :, 32 * i:32 * (i + 1), 32 * j:32 * (j + 1)]
                # 局部分支的卷积和归一化 [下面是局部的紫色块]
                x_p = self.conv1_p(x_p)
                x_p = self.bn1_p(x_p)
                x_p = self.relu(x_p)

                x_p = self.conv2_p(x_p)
                x_p = self.bn2_p(x_p)
                x_p = self.relu(x_p)

                x_p = self.conv3_p(x_p)
                x_p = self.bn3_p(x_p)
                x_p = self.relu(x_p)

                # 通过局部分支的网络层
                x1_p = self.layer1_p(x_p)
                x2_p = self.layer2_p(x1_p)
                x3_p = self.layer3_p(x2_p)
                x4_p = self.layer4_p(x3_p)

                # 局部分支的解码过程
                x_p = F.relu(F.interpolate(self.decoder1_p(x4_p), scale_factor=(2, 2), mode='bilinear'))
                x_p = torch.add(x_p, x4_p)  # 数值相加，不影响通道数和长宽
                x_p = F.relu(F.interpolate(self.decoder2_p(x_p), scale_factor=(2, 2), mode='bilinear'))
                x_p = torch.add(x_p, x3_p)
                x_p = F.relu(F.interpolate(self.decoder3_p(x_p), scale_factor=(2, 2), mode='bilinear'))
                x_p = torch.add(x_p, x2_p)
                x_p = F.relu(F.interpolate(self.decoder4_p(x_p), scale_factor=(2, 2), mode='bilinear'))
                x_p = torch.add(x_p, x1_p)
                x_p = F.relu(F.interpolate(self.decoder5_p(x_p), scale_factor=(2, 2), mode='bilinear'))

                # 将局部分支的输出放回对应的位置
                x_loc[:, :, 32 * i:32 * (i + 1), 32 * j:32 * (j + 1)] = x_p

        # 将全局分支和局部分支的特征图相加
        x = torch.add(x, x_loc)
        x = F.relu(self.decoderf(x))

        # 最终调整输出通道数并应用Softmax
        x = self.adjust(x)

        return nn.Sigmoid()(x)  # 单分类使用Sigmoid

    def forward(self, x):
        """
        前向传播函数。

        参数:
            x (torch.Tensor): 输入张量。

        返回:
            torch.Tensor: 模型输出。
        """
        return self._forward_impl(x)


class AxialAttention_dynamic(nn.Module):
    """
    动态轴向注意力机制模块。

    参数:
        in_planes (int): 输入通道数。
        out_planes (int): 输出通道数。
        groups (int, 可选): 分组数，默认值为8。
        kernel_size (int, 可选): 卷积核大小，默认值为56。
        stride (int, 可选): 步幅，默认值为1。
        bias (bool, 可选): 是否使用偏置，默认值为False。
        width (bool, 可选): 是否为宽度方向，默认值为False。
    """

    def __init__(self, in_planes, out_planes, groups=8, kernel_size=56,
                 stride=1, bias=False, width=False):
        assert (in_planes % groups == 0) and (out_planes % groups == 0)
        super(AxialAttention_dynamic, self).__init__()
        self.in_planes = in_planes
        self.out_planes = out_planes
        self.groups = groups
        self.group_planes = out_planes // groups
        self.kernel_size = kernel_size
        self.stride = stride
        self.bias = bias
        self.width = width

        # 多头自注意力机制的QKV转换
        self.qkv_transform = qkv_transform(in_planes, out_planes * 2, kernel_size=1, stride=1,
                                           padding=0, bias=False)
        self.bn_qkv = nn.BatchNorm1d(out_planes * 2)
        self.bn_similarity = nn.BatchNorm2d(groups * 3)
        self.bn_output = nn.BatchNorm1d(out_planes * 2)

        # 优先编码的初始值
        # 设置False代表不会更训练的参数，不符合论文,设不设置影响不大
        self.f_qr = nn.Parameter(torch.tensor(0.1), requires_grad=False)
        self.f_kr = nn.Parameter(torch.tensor(0.1), requires_grad=False)
        self.f_sve = nn.Parameter(torch.tensor(0.1), requires_grad=False)
        self.f_sv = nn.Parameter(torch.tensor(1.0), requires_grad=False)

        # 位置嵌入
        self.relative = nn.Parameter(torch.randn(self.group_planes * 2, kernel_size * 2 - 1), requires_grad=True)
        query_index = torch.arange(kernel_size).unsqueeze(0)
        key_index = torch.arange(kernel_size).unsqueeze(1)
        relative_index = key_index - query_index + kernel_size - 1
        self.register_buffer('flatten_index', relative_index.view(-1))

        # 如果步幅大于1，添加平均池化层
        if stride > 1:
            self.pooling = nn.AvgPool2d(stride, stride=stride)

        self.reset_parameters()

    def forward(self, x):
        """
        前向传播函数。

        参数:
            x (torch.Tensor): 输入张量，形状为[N, C, H, W]。

        返回:
            torch.Tensor: 输出张量。
        """
        if self.width:
            # 如果是宽度方向，调整张量维度
            x = x.permute(0, 2, 1, 3)
        else:
            # 默认调整为[N, W, C, H]
            x = x.permute(0, 3, 1, 2)
        N, W, C, H = x.shape
        x = x.contiguous().view(N * W, C, H)

        # QKV转换
        qkv = self.bn_qkv(self.qkv_transform(x))
        q, k, v = torch.split(qkv.reshape(N * W, self.groups, self.group_planes * 2, H),
                              [self.group_planes // 2, self.group_planes // 2, self.group_planes], dim=2)

        # 计算位置嵌入
        all_embeddings = torch.index_select(self.relative, 1, self.flatten_index).view(self.group_planes * 2,
                                                                                       self.kernel_size,
                                                                                       self.kernel_size)
        q_embedding, k_embedding, v_embedding = torch.split(all_embeddings,
                                                            [self.group_planes // 2, self.group_planes // 2,
                                                             self.group_planes], dim=0)
        qr = torch.einsum('bgci,cij->bgij', q, q_embedding)
        kr = torch.einsum('bgci,cij->bgij', k, k_embedding).transpose(2, 3)
        qk = torch.einsum('bgci, bgcj->bgij', q, k)

        # 乘以预设的因子
        qr = torch.mul(qr, self.f_qr)
        kr = torch.mul(kr, self.f_kr)

        # 拼接相似度矩阵
        stacked_similarity = torch.cat([qk, qr, kr], dim=1)
        stacked_similarity = self.bn_similarity(stacked_similarity).view(N * W, 3, self.groups, H, H).sum(dim=1)

        # 应用Softmax归一化
        similarity = F.softmax(stacked_similarity, dim=3)

        # 计算SV和SVE
        sv = torch.einsum('bgij,bgcj->bgci', similarity, v)
        sve = torch.einsum('bgij,cij->bgci', similarity, v_embedding)

        # 乘以预设的因子
        sv = torch.mul(sv, self.f_sv)
        sve = torch.mul(sve, self.f_sve)

        # 拼接输出
        stacked_output = torch.cat([sv, sve], dim=-1).view(N * W, self.out_planes * 2, H)
        output = self.bn_output(stacked_output).view(N, W, self.out_planes, 2, H).sum(dim=-2)

        if self.width:
            output = output.permute(0, 2, 1, 3)
        else:
            output = output.permute(0, 2, 3, 1)

        if self.stride > 1:
            output = self.pooling(output)

        return output

    def reset_parameters(self):
        """
        初始化权重参数。
        """
        self.qkv_transform.weight.data.normal_(0, math.sqrt(1. / self.in_planes))
        nn.init.normal_(self.relative, 0., math.sqrt(1. / self.group_planes))


class AxialBlock_dynamic(nn.Module):
    """
    动态轴向注意力块。

    参数:
        inplanes (int): 输入通道数。
        planes (int): 输出通道数。
        stride (int, 可选): 步幅，默认值为1。
        downsample (nn.Module, 可选): 下采样模块，默认值为None。
        groups (int, 可选): 分组数，默认值为1。
        base_width (int, 可选): 基础宽度，默认值为64。
        dilation (int, 可选): 膨胀率，默认值为1。
        norm_layer (nn.Module, 可选): 归一化层，默认使用BatchNorm2d。
        kernel_size (int, 可选): 卷积核大小，默认值为56。
    """
    expansion = 2

    def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
                 base_width=64, dilation=1, norm_layer=None, kernel_size=56):
        super(AxialBlock_dynamic, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        width = int(planes * (base_width / 64.))

        # 下采样卷积层
        self.conv_down = conv1x1(inplanes, width)
        self.bn1 = norm_layer(width)

        # 高度和宽度方向的轴向注意力模块
        self.hight_block = AxialAttention_dynamic(width, width, groups=groups, kernel_size=kernel_size)
        self.width_block = AxialAttention_dynamic(width, width, groups=groups, kernel_size=kernel_size, stride=stride,
                                                  width=True)
        self.conv_up = conv1x1(width, planes * self.expansion)
        self.bn2 = norm_layer(planes * self.expansion)
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        """
        前向传播函数。

        参数:
            x (torch.Tensor): 输入张量。

        返回:
            torch.Tensor: 输出张量。
        """
        identity = x

        # 下采样和激活
        out = self.conv_down(x)
        out = self.bn1(out)
        out = self.relu(out)

        # 通过高度和宽度方向的注意力模块
        out = self.hight_block(out)
        out = self.width_block(out)
        out = self.relu(out)

        # 上采样
        out = self.conv_up(out)
        out = self.bn2(out)

        # 如果需要下采样，则对identity进行下采样
        if self.downsample is not None:
            identity = self.downsample(x)

        # 残差连接和激活
        out += identity
        out = self.relu(out)

        return out


class AxialAttention_wopos(nn.Module):
    """
    轴向注意力模块（无位置嵌入）。

    参数:
        in_planes (int): 输入通道数。
        out_planes (int): 输出通道数。
        groups (int, 可选): 分组数，默认值为8。
        kernel_size (int, 可选): 卷积核大小，默认值为56。
        stride (int, 可选): 步幅，默认值为1。
        bias (bool, 可选): 是否使用偏置，默认值为False。
        width (bool, 可选): 是否为宽度方向，默认值为False。
    """

    def __init__(self, in_planes, out_planes, groups=8, kernel_size=56,
                 stride=1, bias=False, width=False):
        assert (in_planes % groups == 0) and (out_planes % groups == 0)
        super(AxialAttention_wopos, self).__init__()
        self.in_planes = in_planes
        self.out_planes = out_planes
        self.groups = groups
        self.group_planes = out_planes // groups
        self.kernel_size = kernel_size
        self.stride = stride
        self.bias = bias
        self.width = width

        # 多头自注意力机制的QKV转换
        self.qkv_transform = qkv_transform(in_planes, out_planes * 2, kernel_size=1, stride=1,
                                           padding=0, bias=False)
        self.bn_qkv = nn.BatchNorm1d(out_planes * 2)
        self.bn_similarity = nn.BatchNorm2d(groups)

        self.bn_output = nn.BatchNorm1d(out_planes * 1)

        if stride > 1:
            self.pooling = nn.AvgPool2d(stride, stride=stride)

        self.reset_parameters()

    def forward(self, x):
        """
        前向传播函数。

        参数:
            x (torch.Tensor): 输入张量，形状为[N, C, H, W]。

        返回:
            torch.Tensor: 输出张量。
        """
        if self.width:
            # 如果是宽度方向，调整张量维度
            x = x.permute(0, 2, 1, 3)
        else:
            # 默认调整为[N, W, C, H]
            x = x.permute(0, 3, 1, 2)
        N, W, C, H = x.shape
        x = x.contiguous().view(N * W, C, H)

        # QKV转换
        qkv = self.bn_qkv(self.qkv_transform(x))
        q, k, v = torch.split(qkv.reshape(N * W, self.groups, self.group_planes * 2, H),
                              [self.group_planes // 2, self.group_planes // 2, self.group_planes], dim=2)

        # 计算QK相似度
        qk = torch.einsum('bgci, bgcj->bgij', q, k)

        # 归一化相似度
        stacked_similarity = self.bn_similarity(qk).reshape(N * W, 1, self.groups, H, H).sum(dim=1).contiguous()
        similarity = F.softmax(stacked_similarity, dim=3)

        # 计算SV
        sv = torch.einsum('bgij,bgcj->bgci', similarity, v)
        sv = sv.reshape(N * W, self.out_planes * 1, H).contiguous()
        output = self.bn_output(sv).reshape(N, W, self.out_planes, 1, H).sum(dim=-2).contiguous()

        if self.width:
            output = output.permute(0, 2, 1, 3)
        else:
            output = output.permute(0, 2, 3, 1)

        if self.stride > 1:
            output = self.pooling(output)

        return output

    def reset_parameters(self):
        """
        初始化权重参数。
        """
        self.qkv_transform.weight.data.normal_(0, math.sqrt(1. / self.in_planes))
        # 注意：无位置嵌入，因此不初始化relative参数


class AxialBlock_wopos(nn.Module):
    """
    轴向注意力块（无位置嵌入）。

    参数:
        inplanes (int): 输入通道数。
        planes (int): 输出通道数。
        stride (int, 可选): 步幅，默认值为1。
        downsample (nn.Module, 可选): 下采样模块，默认值为None。
        groups (int, 可选): 分组数，默认值为1。
        base_width (int, 可选): 基础宽度，默认值为64。
        dilation (int, 可选): 膨胀率，默认值为1。
        norm_layer (nn.Module, 可选): 归一化层，默认使用BatchNorm2d。
        kernel_size (int, 可选): 卷积核大小，默认值为56。
    """
    expansion = 2

    def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
                 base_width=64, dilation=1, norm_layer=None, kernel_size=56):
        super(AxialBlock_wopos, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        width = int(planes * (base_width / 64.))

        # 下采样卷积层
        self.conv_down = conv1x1(inplanes, width)
        self.conv1 = nn.Conv2d(width, width, kernel_size=1)
        self.bn1 = norm_layer(width)

        # 高度和宽度方向的轴向注意力模块（无位置嵌入）
        self.hight_block = AxialAttention_wopos(width, width, groups=groups, kernel_size=kernel_size)
        self.width_block = AxialAttention_wopos(width, width, groups=groups, kernel_size=kernel_size, stride=stride,
                                                width=True)
        self.conv_up = conv1x1(width, planes * self.expansion)
        self.bn2 = norm_layer(planes * self.expansion)
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        """
        前向传播函数。

        参数:
            x (torch.Tensor): 输入张量。

        返回:
            torch.Tensor: 输出张量。
        """
        identity = x

        # 下采样和激活
        out = self.conv_down(x)
        out = self.bn1(out)
        out = self.relu(out)

        # 通过高度和宽度方向的注意力模块
        out = self.hight_block(out)
        out = self.width_block(out)

        # 激活
        out = self.relu(out)

        # 上采样
        out = self.conv_up(out)
        out = self.bn2(out)

        # 如果需要下采样，则对identity进行下采样
        if self.downsample is not None:
            identity = self.downsample(x)

        # 残差连接和激活
        out += identity
        out = self.relu(out)

        return out


def MedT(pretrained=False, **kwargs):
    """
    创建MedT模型实例。

    参数:
        pretrained (bool, 可选): 是否加载预训练权重，默认值为False。
        **kwargs: 其他关键字参数。

    返回:
        medt_net: MedT模型实例。
    """
    model = medt_net(AxialBlock_dynamic, AxialBlock_wopos, [1, 2, 4, 1], s=0.125, **kwargs)
    return model


if __name__ == '__main__':
    # 创建模型并测试
    x = torch.rand(1, 3, 224, 224)  # 随机生成一个输入张量
    model = MedT()  # 实例化MedT模型

    # 打印模型的总参数量
    print(f'总参数量: {sum(param.numel() for param in model.parameters())}')

    # 遍历模型参数并输出每一层的名字和参数量
    # for name, param in model.named_parameters():
    #     print(f"层名: {name}, 参数数量: {param.numel()}")

    pred = model(x)  # 前向传播
    print(pred.shape)  # 输出预测结果的形状

    # from torch.utils.tensorboard import SummaryWriter

    # 使用TensorBoard记录模型结构
    # writer = SummaryWriter(log_dir="../runs")
    # writer.add_graph(model, input_to_model=torch.rand(1, 3, 224, 224))
    # writer.close()
